﻿using System;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

namespace zijian666.AnyExtensions;

/// <summary>
/// <seealso cref="Object"/> 类型的拓展方法
/// </summary>
public static class ObjectExtensions
{

    /// <summary>
    /// 判断条件后确定是否执行操作
    /// </summary>
    public static TResult If<T, TResult>(this T source, bool condition, Func<T, TResult>? truthy, Func<T, TResult>? falsy = null)
    {
        var func = (condition ? truthy : falsy) ?? throw new ArgumentNullException(condition ? nameof(truthy) : nameof(falsy));
        return func(source);
    }

    /// <summary>
    /// 判断条件后确定是否执行操作
    /// </summary>
    public static void If<T>(this T source, bool condition, Action<T>? truthy, Action<T>? falsy = null)
    {
        var action = condition ? truthy : falsy;
        action?.Invoke(source);
    }


    /// <summary>
    /// 如果对象实现了 <seealso cref="IDisposable"/>接口则尝试释放对象, 且忽略异常
    /// </summary>
    public static void TryDispose(this object? obj)
    {
        try
        {
            if (obj is IDisposable d)
            {
                d.Dispose();
            }
#if NET6_0_OR_GREATER
            else if (obj is IAsyncDisposable d2)
            {
                d2.DisposeAsync().Wait();
            }
#endif
        }
        catch (Exception e)
        {
            Trace.TraceError(e.ToString());
        }
    }

    /// <summary>
    /// 如果 <paramref name="condition"/>为 <see langword="true" /> 则抛出异常
    /// </summary>
    /// <exception cref="ObjectDisposedException"></exception>
    public static void ThrowIfDisposed(this object? obj,
#if NET6_0_OR_GREATER
[DoesNotReturnIf(true)]
#endif
    bool condition, string? message = null)
    {
        if (condition)
        {
            throw new ObjectDisposedException(message);
        }
    }

#if NET6_0_OR_GREATER

    /// <summary>
    /// 如果对象实现了 <seealso cref="IDisposable"/>接口则尝试释放对象, 且忽略异常
    /// </summary>
    public static ValueTask TryDisposeAsync(this object? obj)
    {
        try
        {
            if (obj is IDisposable d)
            {
                d.Dispose();
            }
            else if (obj is IAsyncDisposable d2)
            {
                return d2.DisposeAsync();
            }
        }
        catch (Exception e)
        {
            Trace.TraceError(e.ToString());
        }
        return ValueTask.CompletedTask;
    }
#endif
}
